
// Copyright (c) 2010, Gong Chengming, NARI-TECH

// This file is written as the answers to the exercise of lecture 1 of the Development traing 2010 in NARI advanced software department.

// Created: Oct. 31, 2010

#include "data_rec.h"

#include <assert.h>
#include <fstream>
#include <string>
#include <vector>

// This function reads the data in the file into a vector of DataRec.
// Input:
//   const std::string& - data file name;
// Output:
//   std:: std::vector<DataRec<T> > & - vector of records read from the file.
// Return int:
//   -1 - Fail to open the input file.
//    0 - Otherwise.

template<class T>
int ReadDataFile(const std::string& file_name, std::vector<DataRec<T> > & data_vec) {
  std::ifstream ifile;
  ifile.open(file_name.c_str());

  if(! ifile.good()) {
    ifile.close();  // TODO: check if this close operation is neccessary.
    std::cerr << "Error opening file : " << file_name << ".\n";
    return -1;
  }

  const int N = 96;
  data_vec.resize(N);

  for(int i = 0; i < N; ++i) {
    ifile >> data_vec[i];
  }

  ifile.close();
  return 0;
}

// The first problem is to find the max. and min. p and q from all the input data.
// Input: 
//   const std::vector<DataRec<T> >& - the data records in a vector.
// Output:
//   std::vector<DataRec<T> >::const_iterator& - iterator of the vector for the record with max. system p.
//   std::vector<DataRec<T> >::const_iterator& - iterator of the vector for the record with max. system q.
// Return int:
//   0: currently always zero.

template<class T>
int Problem1(const std::vector<DataRec<T> > & data_vec) {

  typedef std::vector<DataRec<T> > vec_type;
  typedef typename vec_type::const_iterator citer_type;

// Initialize the max_sys_p_iter and max_sys_q_iter.
  citer_type max_sys_p_iter(data_vec.begin());
  citer_type max_sys_q_iter(data_vec.begin());
  citer_type min_sys_p_iter(data_vec.begin());
  citer_type min_sys_q_iter(data_vec.begin());

// Go through all the data to check greater p and greater q and update the max_sys_p_iter and max_sys_q_iter if find any.
  for(typename std::vector<DataRec<T> >::const_iterator iter = data_vec.begin(); iter != data_vec.end(); ++iter) {
     if(iter->m_sys_p > max_sys_p_iter->m_sys_p) {
       max_sys_p_iter = iter;
     }
     if(iter->m_sys_q > max_sys_q_iter->m_sys_q) {
       max_sys_q_iter = iter;
     }
     if(iter->m_sys_p < min_sys_p_iter->m_sys_p) {
       min_sys_p_iter = iter;
     }
     if(iter->m_sys_q < min_sys_q_iter->m_sys_q) {
       min_sys_q_iter = iter;
     }
  }

  assert(max_sys_p_iter != data_vec.end());
  assert(max_sys_q_iter != data_vec.end());
  assert(min_sys_p_iter != data_vec.end());
  assert(min_sys_q_iter != data_vec.end());
  std::cout << "\nResults for problem 1:\n";
  std::cout << "  The system P reached the max " << max_sys_p_iter->m_sys_p << " at " << max_sys_p_iter->m_dstr << " " << max_sys_p_iter->m_tstr << std::endl;
  std::cout << "  The system Q reached the max " << max_sys_q_iter->m_sys_q << " at " << max_sys_q_iter->m_dstr << " " << max_sys_q_iter->m_tstr << std::endl;
  std::cout << "  The system P reached the min " << min_sys_p_iter->m_sys_p << " at " << min_sys_p_iter->m_dstr << " " << min_sys_p_iter->m_tstr << std::endl;
  std::cout << "  The system Q reached the min " << min_sys_q_iter->m_sys_q << " at " << min_sys_q_iter->m_dstr << " " << min_sys_q_iter->m_tstr << std::endl;
  std::cout << "\n";

  return 0;
}

//To get get the average p and average q in the data vector.
template<class T>
int AvgPQ(const std::vector<DataRec<T> > & data_vec, T & avg_p, T& avg_q) {
  avg_p = 0.;
  avg_q = 0.;
  for(int i = 0; i < data_vec.size(); ++i) {
    avg_p += data_vec[i].m_sys_p;
    avg_q += data_vec[i].m_sys_q;
  }
  if(!data_vec.empty()) {
    avg_p /= data_vec.size();
    avg_q /= data_vec.size();
  }
  
  return 0;
}

//This funciton gives the answers for problem 2
template<class T1, class T2>
int Problem2(const std::vector<DataRec<T1> > & data_vec1, const std::vector<DataRec<T2> >& data_vec2){
  std::cout << "\nResults for problem 2:\n";
  T1 avg_p1;
  T1 avg_q1;
  AvgPQ(data_vec1, avg_p1, avg_q1);
  T2 avg_p2;
  T2 avg_q2;
  AvgPQ(data_vec2, avg_p2, avg_q2);
  std::cout.precision(8);
  std::cout << "Avg: " << avg_p1 << " " << avg_p2 << " " << avg_q1 << " " << avg_q2 << std::endl;
  std::cout << "\n";
  return 0;
}

// Get solutions for the two problems.
int main() {
  const std::string IFILE_NAME = "/home/gong/sandbox/material/training/dev2010/lecture1/96data.txt";

// Read data from file.
  typedef float VT1;
  typedef double VT2;
  typedef std::vector<DataRec<VT1> > DataRecVec1;
  typedef std::vector<DataRec<VT2> > DataRecVec2;
  DataRecVec1 data_vec1;
  DataRecVec2 data_vec2;

  if((ReadDataFile(IFILE_NAME, data_vec1) != 0) || (ReadDataFile(IFILE_NAME, data_vec2) != 0)) {
    std::cerr << "Error reading data from file.\n";
    return -1;
  }

  if(data_vec1.empty() || data_vec2.empty()) {
    std::cerr << "No data read.\n";
    return -2;
  }
  
// Get the answer for problem 1.
  Problem1(data_vec1);
  

// Get the answer for problem 2.
  Problem2(data_vec1, data_vec2);

  return 0;
}

